package src.graph;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import src.util.MiniMap;
import src.util.MiniSet;

import checkers.interning.quals.Interned;
import checkers.javari.quals.ReadOnly;
import checkers.javari.quals.Mutable;
import checkers.nullness.quals.NonNull;
import checkers.nullness.quals.Nullable;
import checkers.quals.DefaultLocation;
import checkers.quals.DefaultQualifier;
@DefaultQualifier(value = "checkers.nullness.quals.NonNull", locations =
{ DefaultLocation.ALL_EXCEPT_LOCALS })
public class Graph {

	Graph() {}

	private final MiniSet<String> nodes = new MiniSet<String>();
	private final MiniMap<String, MiniSet<String>> edges = new MiniMap<String, MiniSet<String>>();
	
	private final Map<String,String> cacheTrue = new HashMap<String,String>();
	private final Map<String,String> cacheFalse = new HashMap<String,String>();
	
	private @Nullable String latest = null;

	public void addNode(String id) {
		nodes.add(id);
		edges.put(id, new MiniSet<String>());
		latest = id.intern();
	}

	public void addEdge(String fromId, String toId) {
		MiniSet<String> image = edges.get(fromId);
		if (image != null)
			image.add(toId);
		cacheFalse.clear();
		cacheTrue.clear();
	}

	public void addUniv(String fromId) {
		edges.put(fromId, new MiniSet<String>());
	}

	public /*@ReadOnly*/ MiniSet<String> nodes() {
		return nodes;
	}

	public /*@ReadOnly*/ MiniMap<String, /*@ReadOnly*/ MiniSet<String>> edges() {
		MiniMap<String, MiniSet<String>> result;
		result = (MiniMap<String, MiniSet<String>>)edges;
		return result;
	}
	
	public String toString() {
		return "I am a Graph!";
	}

	public /*@ReadOnly*/ @Nullable MiniSet<String> succesors(String id) {
		return edges.get(id);
	}

	public boolean isLatest(String i) {
		return latest == i;
	}

	public boolean containsEdge(String fromId, String toId) {
		if (hitCache(fromId, toId, cacheTrue) || hitCache(fromId,toId,cacheFalse)) {
			return true;
		} else {
			boolean found;
			if (edges.containsKey(fromId)) {
				MiniSet<String> succesors = edges.get(fromId);
				if (succesors!=null){
					found = succesors.contains(toId);
				} else {
					found = true;
				}
			} else
				found = false;
			
			if (found)
				cacheTrue.put(fromId, toId);
			else
				cacheFalse.put(fromId, toId);
			return found;
		}
	}

	private static boolean hitCache(String fromId, String toId, Map<String, String> cache) {
		if (cache.containsKey(fromId)) {
			if (cache.get(fromId) != null) {
				return cache.get(fromId).equals(toId);
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	public boolean equals(Object obj) {
		return false;
	}
	
}
